import { PaginationQueryDto } from './../dto/paginationQuery.dto';
import { BadRequestException } from '@nestjs/common';
import { FindManyOptions, FindOneOptions, Repository } from 'typeorm';
import { getPaginationData, getWhere } from '../../utils/dataUtil';

export class CommonRepService<T, C = any, U = any, Q extends PaginationQueryDto = any> {

    relations: string[] = [];
    constructor(readonly repository: Repository<T>) { }

    /** 新增一条数据
     * @param data 对应实体类实例
     */
    async createOne(data: C): Promise<any> {
        await this.repository.save(data);
    }

    /** 根据id，查一条数据
     * @param id 
     * @param options 
     * @returns 
     */
    async findOneById(id: string, options?: FindOneOptions<T>): Promise<T> {
        const theOne = await this.repository.findOne(id, { relations: this.relations, ...options })
        if (!theOne) {
            throw new BadRequestException('此条数据不存在');
        }
        return theOne;
    }

    async pagination(data: Q, options?: FindManyOptions<T>): Promise<{ list: T[], total: number }> {
        const { skip, take } = getPaginationData(data);
        const { where, order, ...option } = options || {};
        const [list, total] = await this.repository.findAndCount({
            skip,
            take,
            where: getWhere(where),
            order: { ...order },
            relations: this.relations,
            ...option,
        });
        return { list, total };
    }
 
    /**
     * 根据id 更新一条数据
     * @param id 
     * @param data 
     * @param options 
     */
    async updateById(id: string, data: U, options?: FindOneOptions<T> & { origin: U }): Promise<any> {

        // origin 为更新数据源，用来过滤多余属性
        if (options?.origin) {
            for (const key in data) {
                if (Object.prototype.hasOwnProperty.call(data, key)) {
                    delete data[key];
                }
            }
        }
        // data.origin
        await this.findOneById(id, options);
        return this.repository.createQueryBuilder()
            .update()
            .set(data)
            .where("id = :id", { id })
            .execute()
    }

    /**
     * 根据id 删除一条数据
     * @param id 
     */
    async deleteById(id: string): Promise<any> {
        await this.findOneById(id);
        return this.repository
            .createQueryBuilder()
            .delete()
            .where("id = :id", { id })
            .execute();
    }
}